package com.example.friendcash.activities;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;
import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.example.friendcash.R;
import com.example.friendcash.components.indexablelist.IndexableListView;
import com.example.friendcash.components.indexablelist.StringMatcher;
import com.example.friendcash.parameters.IntentConstants;
import com.example.friendcash.utils.collections.Sequences;
import com.example.friendcash.utils.files.Files;
import com.example.friendcash.utils.functions.IIn;
import com.google.common.base.Supplier;

import java.util.*;

import static android.provider.ContactsContract.Contacts.*;
import static com.google.common.base.Suppliers.memoize;

public class PickFriendsActivity extends SherlockActivity {

    private List<Contact> contacts = new ArrayList<Contact>();
    private ContentAdapter adapter;
    private AlertDialog alertDialog;

    private final static String[] PROJECTION = new String[]{_ID, DISPLAY_NAME, STARRED};
    private final static String SELECTION = HAS_PHONE_NUMBER + " = '1'";
    private final Set<Integer> selection = new HashSet<Integer>();

    private Uri fileUri;

    private String mSections = "#ABCDEFGHIJKLMNOPQRSTUVWXYZАБВГДЕЄЖЗИІЙКЛМНОПРСТУФХЦЧШЩЮЯ";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setTitle(R.string.pick_friends);
        setContentView(R.layout.pick_friends_activity);

        adapter = new ContentAdapter(this, android.R.layout.simple_list_item_1, contacts);

        final IndexableListView listView = (IndexableListView) findViewById(R.id.listview);
        listView.setAdapter(adapter);
        listView.setFastScrollEnabled(true);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                final Contact contact = contacts.get(position);
                if ( !contact.isHeader ) {
                    final boolean isPreviouslySelected = selection.contains(position);
                    if ( isPreviouslySelected ) {
                        selection.remove(position);
                    } else {
                        selection.add(position);
                    }
                    setSelected(!isPreviouslySelected, view);
                    invalidateOptionsMenu();
                }
            }
        });

        loader.loadAndShow(SELECTION);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getSupportMenuInflater().inflate(R.menu.pick_friends_menu, menu);
        if (selection.size() == 0) {
            menu.findItem(R.id.add_selected_friends_button).setEnabled(false);
        }
        return true;
    }

    @SuppressWarnings("UnusedDeclaration")
    public void addSelectedFriendsHandler(MenuItem item) {
        final Intent intent = new Intent();
        intent.putStringArrayListExtra(IntentConstants.NAMES, (ArrayList<String>)getSelectedNames());
        setResult(RESULT_OK, intent);
        finish();
    }

    private void addToContactListDialog() {
        alertDialog = new AlertDialog.Builder(this).create();
        final LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        final View inflateView = layoutInflater.inflate(R.layout.add_new_friend_dialog, null);
        alertDialog.setView(inflateView);
        alertDialog.setTitle("New Contact");
        alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "Save", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        inflateView.findViewById(R.id.new_friend_image).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
                    // handle case of no SDCARD present
                } else {
                    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    fileUri = Files.getOutputMediaFileUri(1);
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
                    intent.putExtra("return-data", true);
                    startActivityForResult(intent, 100);
                }
            }
        });
        alertDialog.show();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == 100) {
            if (resultCode == RESULT_OK) {
                final Bitmap bitmap = BitmapFactory.decodeFile(fileUri.getEncodedPath());
                ((ImageView)alertDialog.findViewById(R.id.new_friend_image)).setImageBitmap(bitmap);
            } else if (resultCode == RESULT_CANCELED) {
                // User cancelled the image capture
            } else {
                // Image capture failed, advise user
            }
        }
    }

    private void chooseFriendAddingMethodDialog() {
        final Dialog dialog=new Dialog(this);
        dialog.setContentView(R.layout.choose_method_dialog);
        dialog.setTitle("Add new friend");
        dialog.findViewById(R.id.add_contact_list).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
                addToContactListDialog();
            }
        });
        dialog.findViewById(R.id.cancel_new_friend_dialog).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
            }
        });
        dialog.show();
    }

    @SuppressWarnings("UnusedDeclaration")
    public void addNewFriendHandler(MenuItem item) {
        chooseFriendAddingMethodDialog();
    }

    private List<String> getSelectedNames() {
        final List<String> result = new ArrayList<String>();
        for ( Integer index : selection ) {
            result.add(contacts.get(index).name);
        }
        return result;
    }

    interface ILoader {
        void loadAndShow(String condition);
    }

    private final ILoader loader = new ILoader() {
        @Override
        public void loadAndShow(final String condition) {
            final Map<String, String> result = memoize(new Supplier<Map<String, String>>() {
                @Override
                public Map<String, String> get() {
                    return getContacts(condition);
                }
            }).get();
            contacts.clear();
            final List<String> collection = new ArrayList<String>(result.keySet());
            Collections.sort(collection, comparator);
            Sequences.each(collection, addElementFunctor);
            if (adapter != null) {
                initHeaders(contacts);
                adapter.notifyDataSetChanged();
            }
        }
    };

    private void initHeaders(List<Contact> contacts) {
        for (int i = 0; i < mSections.length(); i++) {
            final char character = mSections.charAt(i);
            for (Contact item : contacts) {
                if (Character.toLowerCase(item.name.charAt(0)) == Character.toLowerCase(character)) {
                    final int index = contacts.indexOf(item);
                    contacts.add(index, new Contact(Character.toString(character), true));
                    break;
                }
            }
        }
    }

    private Map<String, String> getContacts(String condition) {
        final Map<String, String> contactMap = new HashMap<String, String>();
        final ContentResolver cr = getContentResolver();
        final Cursor cursor = cr.query(CONTENT_URI, PROJECTION, condition, null, null);
        while (cursor.moveToNext()) {
            final String contactID = cursor.getString(cursor.getColumnIndex(_ID));
            final Intent intent = new Intent(Intent.ACTION_VIEW);
            final Uri uri = Uri.withAppendedPath(CONTENT_URI, String.valueOf(contactID));
            intent.setData(uri);
            final String title = (cursor.getString(cursor.getColumnIndex(DISPLAY_NAME)));
            contactMap.put(title, intent.toUri(0));
        }
        cursor.close();
        return contactMap;
    }

    private static final Comparator<String> comparator = new Comparator<String>() {
        @Override
        public int compare(String first, String second) {
            return first.compareTo(second);
        }
    };

    private class ContentAdapter extends ArrayAdapter<Contact> implements SectionIndexer {

        public ContentAdapter(Context context, int textViewResourceId,
                              List<Contact> objects) {
            super(context, textViewResourceId, objects);
        }

        @Override
        public int getPositionForSection(int section) {
            // If there is no item for current section, previous section will be selected
            for (int i = section; i >= 0; i--) {
                for (int j = 0; j < getCount(); j++) {
                    if (i == 0) {
                        // For numeric section
                        for (int k = 0; k <= 9; k++) {
                            if (StringMatcher.match(String.valueOf(getItem(j).name.charAt(0)), String.valueOf(k)))
                                return j;
                        }
                    } else {
                        if (StringMatcher.match(String.valueOf(getItem(j).name.charAt(0)), String.valueOf(mSections.charAt(i))))
                            return j;
                    }
                }
            }
            return 0;
        }

        @Override
        public int getSectionForPosition(int position) {
            return 0;
        }

        @Override
        public Object[] getSections() {
            String[] sections = new String[mSections.length()];
            for (int i = 0; i < mSections.length(); i++)
                sections[i] = String.valueOf(mSections.charAt(i));
            return sections;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            final Contact contact = contacts.get(position);
            final TextView view = (TextView) super.getView(position, convertView, parent);
            view.setTextColor(Color.WHITE);
            if (contact.isHeader) {
                view.setBackgroundColor(Color.rgb(220, 127, 127));
                view.setTypeface(null, Typeface.BOLD);
            } else {
                view.setBackgroundColor(Color.BLACK);
                view.setTypeface(null, Typeface.NORMAL);
            }
            view.setTextSize(16);
            view.setMaxLines(2);
            view.setText(contact.name);
            return view;
        }
    }

    private static void setSelected(boolean isSelected, View view) {
        view.setBackgroundColor(isSelected ? Color.argb(255, 154, 210, 96) : Color.BLACK);
    }

    class Contact {

        public final String name;
        public final boolean isHeader;

        Contact(String name, boolean isHeader) {
            this.name = name;
            this.isHeader = isHeader;
        }
    }

    private final IIn<String> addElementFunctor = new IIn<String>() {
        @Override
        public void in(String name) {
            contacts.add(new Contact(name, false));
        }
    };

}
